#include <avr/io.h>
#include <avr/interrupt.h>

#ifndef F_CPU
//#warning "F_CPU war noch nicht definiert, wird nun mit 3686400 definiert"
#define F_CPU 3686400UL     /* Quarz mit 3.6864 Mhz */
#endif
#include <util/delay.h>

#include "uart.h"
#define BAUD 9600UL
#define UBRR_VAL ((F_CPU+BAUD*8)/(BAUD*16)-1)
#define BAUD_REAL (F_CPU/(16*(UBRR_VAL+1)))
#define BAUD_ERROR ((BAUD_REAL*1000)/BAUD-1000)

#if ( BAUD_ERROR>10)
#error "Baud-Rate causes errors > 1 percent!!!"
#endif

#define LEDSOUT PORTB
#define LEDSCTRL DDRB
#define SWITCHESIN PINC
#define SWITCHESCTRL DDRC

enum STATE_MAIN
{
  eSTATE_MIN,
  eSTATE_INIT,
  eSTATE_CHECK_TWI,
  eSTATE_MAINLOOP,
  eSTATE_RESET,
  eSTATE_ERROR
};

enum ERRORS
{
  eERROR_NONE,
  eERROR_BADADR,
  eERROR_BADVALUE,
  eERROR_BADSTATE,
  eERROR_UART_OVERFLOW,
  eERROR_TWI_OVERFLOW,
  eERROR_TIMEOUT,
  eERROR_MAX
};

enum ERRORS lastError = eERROR_NONE;
enum STATE_MAIN state = eSTATE_MIN;
enum STATE_MAIN laststate = eSTATE_ERROR;
uint8_t g_iConnectedSlaves = 0;
uint8_t switches;
uint8_t changedvalue;
uint8_t changedbit;
/*
 * uint8_t segmentcode[10] =
 { 0b11000000, 0b11111001, 0b10100100, 0b10110000, 0b10011001, 0b10010010,
 0b10000010, 0b11111000, 0b10000000, 0b10010000 };*/

unsigned char segmentcode[10] =
{ 0xC0, 0xbF9, 0xA4, 0xB0, 0x99, 0x92,
  0x82, 0xF8, 0x80, 0x90 };

  void
init(void)
{
  // output only on LED-Port
  LEDSCTRL = 0xff;
  // turn all LEDs on
  LEDSOUT = 0x00;

  // input only on Switches-Port
  SWITCHESCTRL = 0x00;
  // get initial switches-state
  switches = SWITCHESIN;

  // init UART
  uart_init();

  // init TWI
  //twi_init();
}

  void
handleSerialInput(void)
{
  uint8_t temp, b1, b2;

  // get waiting bytes from serial connection
  b1 = uart_getc_wait();
  b2 = uart_getc_wait();
  if(b1 == 0)
  {
    state = eSTATE_RESET;
  } else if(b1 == 1 || b1 == 3)
  {
    // was a test/ping?
    uart_putc(1);
    uart_putc(3);
  } else
  {
    // TODO 02 parse the incoming bytes
    if(b1 == 254)
    {
      // set command for myself - LEDs
      temp = b2 & 0x1; // save the value
      b2 = b2 >> 3;
      b2 = b2 - 8;
      changedbit = 1 << (b2 - 1);
      if(temp > 0)
        changedvalue = PINB & ~changedbit;
      else
        changedvalue = PINB | changedbit;
      LEDSOUT = changedvalue;
    }
  }

}
  int
main(void)
{
  uint8_t i, temp, count=0, oldswitches;

  LEDSOUT = 0xFF; // LEDs OFF

  // now loop forever
  while (1)
  {
    // if no switch pressed, display current state
    //		if(SWITCHESIN == 0xFF)
    //		{
    //			//displayOnSegment(g_iConnectedSlaves);
    //			temp = g_iConnectedSlaves << 3;
    //			temp |= state + 1;
    //			LEDSOUT = 254;
    //			//LEDSOUT = ~temp;
    //			laststate = state;
    //		}

    switch(state)
    {
      case eSTATE_MIN:
        state = eSTATE_INIT;
        break;
      case eSTATE_INIT:
        init();
        // interrupts ON
        sei();
        state = eSTATE_CHECK_TWI;
        break;
      case eSTATE_CHECK_TWI:
        for (i = 1; i < 64; ++i)
        {
          // signal currently checked slave
          LEDSOUT = ~((i << 3) + state + 1);
          // TODO 01 add TWI/I2C-check
          _delay_ms(10);
        }
        state = eSTATE_MAINLOOP;
        break;

      case eSTATE_MAINLOOP:
        // check switches
        if(SWITCHESIN != 0xFF)
        {
          oldswitches=SWITCHESIN;
          if(~SWITCHESIN & 0x01)
          {
            // check: turn all LEDs ON
            LEDSOUT = 0x00;
          }
          if(~SWITCHESIN & 0x02)
          {
            // check: turn all LEDs OFF
            LEDSOUT = 0xFF;
            count=0;
            LEDSOUT = (segmentcode[0]);//lastError;
          }
          if(~SWITCHESIN & 0x04)
          {
            // check last error
            if (++count>9)
              count=0;
            LEDSOUT = (segmentcode[count]);//lastError;
            _delay_ms(100);
          }
        }

        // check for overflow of serial-output (must not happen!)
        if(uart_put_waiting() > 0x3E)
        {
          state = eSTATE_ERROR;
          lastError = eERROR_UART_OVERFLOW;
        }

        if(uart_get_possible() >= 2)
          handleSerialInput();

        break;
      case eSTATE_RESET:
        // it was an init - so response ASAP
        uart_putc(0);
        uart_putc(0);
        state = eSTATE_INIT;
        g_iConnectedSlaves = 0;
        break;
      case eSTATE_ERROR:
      default:
        // ERROR!
        while (1)
        {
          LEDSOUT = 0xAA;
          _delay_ms(500);
          LEDSOUT = ~lastError;
          _delay_ms(500);
        }
        break;
    }
  }

  // pointless, will never be reached
  LEDSOUT = 0xAA;
  return 0;
}
